use std::fs;
use std::net::Ipv4Addr;
use std::str::FromStr;

use tauri_plugin_opener::OpenerExt;

#[tauri::command]
fn greet(name:String)-> String {
    format!("Hi, {}, this's greet from Tauri!", name)
}

/// 将 Ipv4Addr 转换为 32 位整数
fn ip_to_u32(ip: Ipv4Addr) -> u32 {
    let octets = ip.octets();
    ((octets[0] as u32) << 24) |
        ((octets[1] as u32) << 16) |
        ((octets[2] as u32) << 8) |
        (octets[3] as u32)
}

/// 将 32 位整数转换为 Ipv4Addr
fn u32_to_ip(n: u32) -> Ipv4Addr {
    Ipv4Addr::new(
        ((n >> 24) & 0xFF) as u8,
        ((n >> 16) & 0xFF) as u8,
        ((n >> 8) & 0xFF) as u8,
        (n & 0xFF) as u8,
    )
}

/// 计算与给定 IP 地址和通配符掩码匹配的所有 IP 地址
fn calculate_matching_ips(ip: Ipv4Addr, wildcard_mask: Ipv4Addr) -> Vec<Ipv4Addr> {
    // 将 IP 和通配符掩码转换为 32 位整数
    let ip_int = ip_to_u32(ip);
    let mask_int = ip_to_u32(wildcard_mask);

    // 计算固定位和可变位
    // 固定位：通配符掩码中为 0 的位，必须精确匹配
    // 可变位：通配符掩码中为 1 的位，可以是 0 或 1
    let fixed_bits = ip_int & !mask_int;
    let variable_mask = mask_int;

    // 计算可变位的数量
    let variable_bits_count = variable_mask.count_ones() as usize;

    // 检查可变位数量，避免生成过多 IP 地址导致性能问题
    if variable_bits_count > 20 {
        eprintln!("错误：通配符掩码包含太多可变位（{}位），可能会生成超过一百万的 IP 地址，这可能导致性能问题。", variable_bits_count);
        std::process::exit(1);
    }

    // 计算可能的 IP 地址数量 (2^variable_bits_count)
    let total_ips = 1u32 << variable_bits_count;

    // 生成所有可能的 IP 地址
    let mut matching_ips = Vec::with_capacity(total_ips as usize);
    for i in 0..total_ips {
        // 将 i 的位填充到可变位的位置
        let mut ip = fixed_bits;
        let mut temp_i = i;

        // 遍历每个位，将 temp_i 的位填充到可变位
        for bit in 0..32 {
            if (variable_mask >> bit) & 1 != 0 {
                ip |= (temp_i & 1) << bit;
                temp_i >>= 1;
            }
        }

        matching_ips.push(u32_to_ip(ip));
    }

    matching_ips
}

#[tauri::command]
fn calculate(ip:String, mask:String)->Result<Vec<Ipv4Addr>, String> {
    // 解析 IP 地址
    let ip = match Ipv4Addr::from_str(&ip) {
        Ok(ip)  => ip,
        Err(_)  => return Err(format!("无效的 IP 地址: {}", &ip)),
    };

    // 解析通配符掩码
    let wildcard_mask = match Ipv4Addr::from_str(&mask) {
        Ok(m)   => m,
        Err(_)  => return Err(format!("无效的通配符掩码: {}", &mask)),
    };

    // 计算所有匹配的 IP 地址
    let matching_ips = calculate_matching_ips(ip, wildcard_mask);
    Ok(matching_ips)
}

#[tauri::command]
fn save_txt(ip:String, mask:String, ips:Vec<String>, filename: Option<String>, app: tauri::AppHandle)-> Result<String, String> {
    // 获取当前 exe 路径
    let exe_path = std::env::current_exe().map_err(|e| e.to_string())?;
    // 获取 exe 所在目录
    let exe_dir = exe_path.parent().ok_or("无法获取程序所在目录")?;

    let filename = filename.unwrap_or_else(|| "temp.txt".to_string());
    let file_path = exe_dir.join(&filename);

    let mut lines = String::new();
    lines.push_str(&format!("{}\n\n", app.package_info().name.clone()));
    lines.push_str(&format!("程序作者\t{}\n", app.package_info().authors));
    lines.push_str("开源代码\thttps://gitcode.com/ssrc0604hx/tauri-wildcard-mask\n");
    lines.push_str("\n");
    lines.push_str(&format!("IP地址\t{}\n", ip));
    lines.push_str(&format!("掩码地址\t{}\n", mask));
    lines.push_str("匹配地址\n");
    for row in ips {
        lines.push_str(&format!("\t\t{}\n", row));
    }

    fs::write(&file_path, lines).map_err(|e| e.to_string())?;

    if let Err(e) = app.opener().open_path(file_path.to_string_lossy().to_string(), None::<&str>) {
        eprintln!("打开文件{}失败：{}", file_path.display(), e);
    }

    Ok(filename)
}

#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
    tauri::Builder::default()
        // .setup(|app| {
        //     #[cfg(debug_assertions)]
        //     {
        //         if let Some(webview) = app.get_webview_window("main") {
        //             webview.open_devtools();
        //         }
        //     }
        //     Ok(())
        // })
        .plugin(tauri_plugin_opener::init())
        .invoke_handler(tauri::generate_handler![greet, calculate, save_txt])
        .run(tauri::generate_context!())
        .expect("error while running tauri application");
}
